package org.dding.web.console;

import java.io.File;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Set;

import org.dding.core.annotation.Service;
import org.dding.core.log.ILogger;
import org.dding.core.log.LoggerFactory;
import org.dding.core.management.ModuleInfo;
import org.dding.core.manager.IModuleManager;
import org.dding.core.util.FileExtUtils;
import org.dding.core.util.StringUtils;
import org.dding.msc.service.ServiceInfoWarehouse;
import org.dding.mvc.ActionSupport;
import org.dding.mvc.InvocationContext;
import org.dding.mvc.PageContext;
import org.dding.mvc.WebContextLoader;
import org.dding.mvc.annotation.ActionMethod;
import org.dding.mvc.annotation.ActionMethod.ForwardMethod;
import org.dding.mvc.util.Pager;
import org.jboss.modules.Module;
import org.jboss.modules.ModuleIdentifier;
import org.jboss.modules.ModuleLoadException;

@Service(name = "moduleAction")
public class ModuleAction extends ActionSupport<Object> {

	private ILogger logger = LoggerFactory.getLogger(getClass());
	private static Map<String, Comparator<WebModuleInfo>> mapping = new HashMap<String, Comparator<WebModuleInfo>>();
	private static String[] properties = { "moduleName", "moduleSlot",
			"moduleUnzip", "moduleServices", "modulePath" };
	private List<WebModuleInfo> list;

	static {
		for (String property : properties) {
			String method = "get" + property.substring(0, 1).toUpperCase()
					+ property.substring(1);
			mapping.put(property, new InternalComparator<WebModuleInfo>(method));
		}
	}

	IModuleManager manager = WebContextLoader.getContainer();

	@ActionMethod(
			name = "loadModule",
			successView = "modulelist.do",
			errorView = "error.html",
			httpMethod = ActionMethod.HttpMethod.GET)
	public void loadModule(InvocationContext invocationContext) throws IOException, ModuleLoadException {
		String moduleName = invocationContext.getParameterValue("moduleName");
		manager.loadModule(moduleName, true);
	}

	@ActionMethod(
			name = "unloadModule",
			errorView = "error.html",
			httpMethod = ActionMethod.HttpMethod.POST,
			forwardMethod = ForwardMethod.FLUSH)
	public void unloadModule(InvocationContext invocationContext) {
		String[] ids = invocationContext.getParameterValues("ids");
		Map<String, String> result = new HashMap<String, String>();
		StringBuilder failids = new StringBuilder();
		boolean skip = false;
		for (String id : ids) {
			boolean unload = manager.unloadModule(id, false);
			if (!unload) {
				failids.append(id);
			}
		}
		if (!skip) {
			if (failids.length() == 0) {
				result.put(STATUS, SUCCESS);
				result.put(MESSAGE, "卸载成功!");
			} else {
				result.put(STATUS, FAILURE);
				result.put(MESSAGE, "卸载失败或被依赖：" + failids.toString());
			}
		}
		list = new ArrayList<WebModuleInfo>();
		ajaxJsonMessage(result, invocationContext);
	}

	@ActionMethod(
			name = "view",
			successView = "main/moduleview.jsp",
			errorView = "error.html",
			httpMethod = ActionMethod.HttpMethod.GET)
	public void view(InvocationContext invocationContext) {
		String id = invocationContext.getParameterValue("id");
		ModuleInfo moduleInfo = manager.getModuleDescription(id);
		WebModuleInfo webModuleInfo = new WebModuleInfo();
		webModuleInfo.setModuleName(ModuleIdentifier.fromString(
				moduleInfo.getName()).getName());
		webModuleInfo.setModuleSlot(ModuleIdentifier.fromString(
				moduleInfo.getName()).getSlot());
		webModuleInfo.setClassLoader(moduleInfo.getClassLoader());
		webModuleInfo.setMainClass(moduleInfo.getMainClass());
		webModuleInfo.setDependInfos(moduleInfo.getDependencies());
		webModuleInfo.setResourceInfos(moduleInfo.getResourceLoaders());

		String modulePath = WebContextLoader._modulesDir + File.separator
				+ FileExtUtils.toPath(moduleInfo.getName());
		webModuleInfo.setModulePath(modulePath);
		webModuleInfo.setUnzip(true);
		List<String> services = ServiceInfoWarehouse.getInstance()
				.getServiceByModule(webModuleInfo.getModuleName());
		webModuleInfo.setServiceNum(services != null ? services.size() : 0);

		PageContext pageContext = invocationContext.getPageContext();
		pageContext.setAttribute("webModuleInfo", webModuleInfo);
	}

	@ActionMethod(
			name = "home",
			successView = "main/main.jsp",
			errorView = "error.html",
			httpMethod = ActionMethod.HttpMethod.GET)
	public void home(InvocationContext invocationContext) {
		PageContext pageContext = invocationContext.getPageContext();
		pageContext.setAttribute("platform", manager.getPlatformInfo());
	}

	@ActionMethod(
			name = "module",
			successView = "main/modulelist.jsp",
			invocationClass = Pager.class)
	public void module(InvocationContext invocationContext) {
		Pager pagerInvocaion = (Pager) invocationContext.getInvocation();

		String keyword = pagerInvocaion.getKeyword();
		String searchBy = pagerInvocaion.getSearchBy();

		if (StringUtils.isNotEmpty(keyword) && StringUtils.isNotEmpty(searchBy)) {
			query(invocationContext);
		} else {
			if (pagerInvocaion != null) {
				fillAllModule();
				Pager pager = handlePager(list, pagerInvocaion);
				String orderBy = pager.getOrderBy();
				if (StringUtils.isNotEmpty(orderBy)) {
					Comparator<WebModuleInfo> comparator = mapping.get(orderBy);
					if (comparator != null)
						Collections.sort(list, comparator);
				}
				invocationContext.getPageContext().setAttribute("pager", pager);
			}
		}
	}

	@ActionMethod(
			name = "modulelist",
			successView = "main/modulelist.jsp",
			httpMethod = ActionMethod.HttpMethod.GET)
	public void list(InvocationContext invocationContext) {
		fillAllModule();
		invocationContext.getPageContext().setAttribute("pager",
				handlePager(list, null));
	}

	@ActionMethod(
			name = "relink",
			httpMethod = ActionMethod.HttpMethod.POST,
			forwardMethod = ForwardMethod.FLUSH)
	public void relink(InvocationContext invocationContext) {
		String name = invocationContext.getParameterValue("id");
		final Module module = manager.findModule(name);
		Map<String, String> result = new HashMap<String, String>();
		try {
			manager.getModuleLoader().relink(module);
			result.put(STATUS, SUCCESS);
			result.put(MESSAGE, "连接成功！");
		} catch (ModuleLoadException e) {
			logger.error(e.getMessage(), e);
			result.put(STATUS, FAILURE);
			result.put(MESSAGE, "连接失败！");
			throw new IllegalStateException("Module load failure for module "
					+ name + ": " + e.toString());
		}
		ajaxJsonMessage(result, invocationContext);
	}

	private void query(InvocationContext invocationContext) {
		Pager pagerInvocaion = (Pager) invocationContext.getInvocation();
		String keyword = pagerInvocaion.getKeyword();
		String searchBy = pagerInvocaion.getSearchBy();
		list = new ArrayList<WebModuleInfo>();
		if ("moduleName".equalsIgnoreCase(searchBy)) {

			Set<ModuleIdentifier> map = manager.getModuleLoader()
					.getModuleMap().keySet();
			for (ModuleIdentifier identifier : map) {
				if (StringUtils.containsIgnoreCase(identifier.toString(),
						keyword)) {
					list.add(findListModule(identifier));
				}
			}
			invocationContext.getPageContext().setAttribute("pager",
					handlePager(list, null));
		} else {
			throw new IllegalArgumentException(
					"only support search by module name.");
		}
	}

	private WebModuleInfo findListModule(ModuleIdentifier identifier) {
		WebModuleInfo webInfo = new WebModuleInfo();
		webInfo.setModuleName(identifier.getName());
		webInfo.setModuleSlot(identifier.getSlot());
		String modulePath = WebContextLoader._modulesDir + File.separator
				+ FileExtUtils.toPath(identifier.getName()) + File.separator
				+ ModuleIdentifier.fromString(identifier.getName()).getSlot();
		webInfo.setModulePath(modulePath);
		webInfo.setUnzip(true);
		List<String> services = ServiceInfoWarehouse.getInstance()
				.getServiceByModule(identifier.toString());
		webInfo.setServiceNum(services != null ? services.size() : 0);
		return webInfo;
	}

	private void fillAllModule() {
		IModuleManager manager = WebContextLoader.getContainer();
		final Set<ModuleIdentifier> identifiers = manager.getModuleLoader()
				.getModuleMap().keySet();
		list = new ArrayList<WebModuleInfo>(identifiers.size());
		for (ModuleIdentifier identifier : identifiers) {
			list.add(findListModule(identifier));
		}
	}
}
